package push2java;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Stack;

public class State {

    public Random random = new Random();
    public Stack<Object> integerStack;
    public Stack<Object> floatStack;
    public Stack<Object> booleanStack;
    public Stack<Object> nameStack;
    public Stack<Object> typeStack;
    public Stack<Object> codeStack;
    public Stack<Object> execStack;
    public Map<String, Object> integerBindings;
    public Map<String, Object> floatBindings;
    public Map<String, Object> booleanBindings;
    public Map<String, Object> nameBindings;
    public Map<String, Object> typeBindings;
    public Map<String, Object> codeBindings;

    public State(List<Expression> program) {
        integerStack = new Stack<Object>();
        floatStack = new Stack<Object>();
        booleanStack = new Stack<Object>();
        nameStack = new Stack<Object>();
        typeStack = new Stack<Object>();
        codeStack = new Stack<Object>();
        execStack = new Stack<Object>();
        integerBindings = new HashMap<String, Object>();
        floatBindings = new HashMap<String, Object>();
        booleanBindings = new HashMap<String, Object>();
        typeBindings = new HashMap<String, Object>();
        nameBindings = new HashMap<String, Object>();
        codeBindings = new HashMap<String, Object>();

        for (int i = program.size() - 1; i >= 0; i--) {
            execStack.push(program.get(i));
        }
    }

    public Stack<Object> stack(Type.Literal type) {
        if (type == Type.Literal.INTEGER) {
            return integerStack;
        } else if (type == Type.Literal.FLOAT) {
            return floatStack;
        } else if (type == Type.Literal.BOOLEAN) {
            return booleanStack;
        } else if (type == Type.Literal.TYPE) {
            return typeStack;
        } else if (type == Type.Literal.NAME) {
            return nameStack;
        } else if (type == Type.Literal.CODE) {
            return codeStack;
        }
        throw new IllegalStateException("No stack of type " + type);
    }

    public Stack<Object> currentStack() {
        if (typeStack.empty()) {
            return floatStack;
        }
        return stack((Type.Literal) typeStack.peek());
    }

    public Map<String, Object> bindings(Type.Literal type) {
        if (type == Type.Literal.INTEGER) {
            return integerBindings;
        } else if (type == Type.Literal.FLOAT) {
            return floatBindings;
        } else if (type == Type.Literal.BOOLEAN) {
            return booleanBindings;
        } else if (type == Type.Literal.TYPE) {
            return typeBindings;
        } else if (type == Type.Literal.NAME) {
            return nameBindings;
        } else if (type == Type.Literal.CODE) {
            return codeBindings;
        }
        throw new IllegalStateException("No stack of type " + type);
    }

        public Map<String, Object> currentBindings() {
        if (typeStack.empty()) {
            return floatBindings;
        }
        return bindings((Type.Literal) typeStack.peek());
    }
}
